import { hasChanged, isObject } from "../shared";
import { isTracking, trackEffects, triggerEffects } from "./effect";
import { reactive } from "./reactive";

class RefImpl {
    private _value: any;
    public dep;
    private _rawValue: any;
    private __v_isRef = true;
    constructor(value) {
        // 存储原始值
        this._rawValue = value;
        // 判断value是不是对象，是则reactive包裹
        this._value = convert(value);

        this.dep = new Set();
    }

    get value() {
        trackRefValue(this)
        return this._value;
    }

    set value(newValue) {
        // 一定是先去修改了value值
        // 判断是否有变化，有变化就去触发effect
        if (hasChanged(newValue, this._rawValue)) {
            this._rawValue = newValue;
            this._value = convert(newValue);
            triggerEffects(this.dep);
        };
    }
}

function convert(value) {
    return isObject(value) ? reactive(value) : value;
}

function trackRefValue(ref) {
    if (isTracking()) {
        trackEffects(ref.dep);
    }
}

export function ref(value) {
    return new RefImpl(value);
}

export function isRef(ref) {
    return !!(ref && ref.__v_isRef);
}

// 返回ref的value或原始值
export function unRef(ref) {
    // 看看是不是一个ref对象 -> 返回ref.value
    // 否则 -> 返回值本身
    return isRef(ref) ? ref.value : ref;
}

export function proxyRefs(objectWithRefs) {
    return new Proxy(objectWithRefs, {
        get(target, key) {
            // 通过unRef直接返回ref的value或非ref的值
            return unRef(Reflect.get(target, key));
        },
        set(target, key, value) {
            // 如果目标的值是ref并且新赋的值不是ref，就直接修改ref的value
            if (isRef(target[key]) && !isRef(value)) {
                return target[key].value = value;
            } else {
            // 否则，直接替换值
                return Reflect.set(target, key, value);
            }
        }
    });
}